#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>

#define NUM 1024
#define SIZE 32
#define SEP " "

// 保存完整的命令行字符串
char cmd_line[NUM];
// 保存打散之后的命令行字符串
char *g_argv[SIZE];
// 写一个环境变量的buffer，防止被覆盖
char env_buff[NUM];

// shell 运行原理：通过让子进程执行命令，父进程等待&&解析命令
int main()
{
    // 0. 命令行解释器，一定是一个常驻内存的进程，不退出
    while(1)
    {
        // 1. 打印提示信息 [zs@localhost myshell]#
        printf("[Mantax@newhost-3-9 myshell]$ ");
        fflush(stdout);

        // 2. 获取输入信息
        memset(cmd_line, '\0', sizeof cmd_line);
        if(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
        {
            continue;
        }

        //字符串去掉\n
        cmd_line[strlen(cmd_line) - 1] = '\0';

        // 3. 命令行字符串解析："ls -l -a" -> "ls" "-l" "-a"
        g_argv[0] = strtok(cmd_line, SEP); // 第一次调用，要传入原始字符串 SEP==" "
        int index = 1;

        if(strcmp(g_argv[0], "ls") == 0)
        {
            g_argv[index++] = (char*)"--color=auto";
        }
        if(strcmp(g_argv[0], "ll") == 0)
        {
            g_argv[0] = (char*)"ls";
            g_argv[index++] = (char*)"-l";
            g_argv[index++] = (char*)"--color=auto";
        }
        while(g_argv[index++] = strtok(NULL, SEP)); // 之后传入NULL继续解析原始字符串
        if(strcmp(g_argv[0], "export") == 0 && g_argv[1] != NULL)
        {
            strcpy(env_buff, g_argv[1]);
            putenv(env_buff);
            continue;
        }
          
        // 4. 让父进程(shell)自己执行的命令，叫做内置命令/内建命令 
        if(strcmp(g_argv[0], "cd") == 0)
        {
            if(g_argv[1] != NULL)
            {   
                chdir(g_argv[1]);
            }
        }



        // 5. fork()
        pid_t id = fork();
        if(id == 0)
        {
            // child
            execvp(g_argv[0], g_argv);
            exit(1);
        }


        // father
        int status = 0;
        pid_t ret = waitpid(id, &status, 0);
        if(ret > 0)
        {
            printf("exit code: %d\n", WEXITSTATUS(status));
        }


    }
}
